<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>《塞尔达传说：王国之泪》桩钢琴</title>
    <script src="script/key.js"></script>
    <script src="script/bpm.js"></script>
    <link rel="stylesheet" href="css/style.css">
</head>

<body onload="init()">
<div id="panel_piano">
    <div id="piano"></div>
    <div id="func">
        <input id="func_play" type="checkbox" checked><label for="func_play">播放桩音</label>
        <input id="func_loop" type="checkbox"><label for="func_loop">循环播放</label>
        <input id="func_show_screenshot" type="checkbox" checked><label for="func_show_screenshot">显示游戏截图</label>
        <input id="func_bpm" type="button" value="BPM查询" style="margin-left: 15px">
        <input id="func_about" type="button" value="关于本工具" style="margin-left: 5px">
    </div>
    <div id="about">
        <div>作者：<a href="https://space.bilibili.com/59389">盖饭ZD</a></div>
        <div>协议：<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC-BY-NC-SA 4.0</a></div>
        <div>工具提供桩音试听和游戏截图，方便各位参考与调试，尽量降低肝度</div>
        <div>本工具<span style="color: red; font-weight: bold;">免费使用</span>，不可用作商业用途。</div>
        <div>所有音频来自《塞尔达传说：王国之泪》游戏录像截取</div>
        <div>所有图片来自《塞尔达传说：王国之泪》游戏截图</div>
        <div style="font-size: 10px; margin-top: 10px; color: black">
            <a class="hide-a" href="https://gitee.com/gaifan/zelda-piano">屎山代码</a>，请勿见怪
        </div>
    </div>
    <div id="div_detail" style="display: none">
        <table id="table_detail">
            <tbody>
                <tr>
                    <td style="width: 50px">音名</td>
                    <td style="width: 100px" id="note_name"></td>
                    <td style="width: 100px" >使用桩数量</td>
                    <td style="width: 50px" id="note_use_count"></td>
                    <td id="note_remark"></td>
                </tr>
                <tr id="tr_note_screenshot">
                    <td colspan="5" id="note_screenshot"></td>
                </tr>
            </tbody>
        </table>
    </div>
</div>
<div id="panel_bpm" style="display: none">
    <label for="input_bpm_search">歌曲BPM</label>
    <input id="input_bpm_search" type="number" style="width: 80px" class="bpm-input">
    <input type="button" id="btn_bpm_search" value="搜">
    <label for="input_bpm_near1" style="margin-left: 15px">首推±</label>
    <input id="input_bpm_near1" type="number" value="3" class="bpm-input">
    <label for="input_bpm_near2" style="margin-left: 5px">次推±</label>
    <input id="input_bpm_near2" type="number" value="6" class="bpm-input">
    <input id="func_piano" style="margin-left: 40px" type="button" value="返回琴键">
    <div>测量存在误差，仅供参考</div>
    <div id="bpm"></div>
</div>
<div id="sound" style="display: none"></div>
<script>
    let clickCounter = 0;
    let curKeyObj = null;

    function init() {
        // 生成键盘和声音
        const pianoDiv = document.getElementById("piano");
        const soundDiv = document.getElementById("sound");
        let curWhiteIndex = 0;
        for (let i = 0; i < KEYS_DATA.length; i++) {
            let keyObj = KEYS_DATA[i];
            let keyDiv = document.createElement("div");
            keyDiv.id = getKeyId(keyObj);
            keyDiv.keyObj = keyObj;
            if (keyObj.name.indexOf("#") < 0) {
                // 白键
                keyDiv.classList.add("white-key");
                if (keyObj.useWall) {
                    keyDiv.classList.add("use-wall");
                } else {
                    keyDiv.classList.add("white-use-" + keyObj.useCount);
                }
                keyDiv.style.marginLeft = (curWhiteIndex * 30) + "px";
                let keyText = document.createElement("span");
                keyText.innerText = keyObj.name;
                keyText.classList.add("white-key-text");
                keyDiv.appendChild(keyText);
                curWhiteIndex++;
            } else {
                // 黑键
                keyDiv.classList.add("black-key");
                if (keyObj.useWall) {
                    keyDiv.classList.add("use-wall");
                } else {
                    keyDiv.classList.add("black-use-" + keyObj.useCount);
                }
                keyDiv.style.marginLeft = (curWhiteIndex * 30 - 10) + "px";
            }
            pianoDiv.appendChild(keyDiv);

            let audio = document.createElement("audio");
            audio.id = "audio_" + keyObj.file;
            audio.src = "sound/" + keyObj.file + ".mp3";
            soundDiv.appendChild(audio);
        }

        // 键盘事件
        const keys = document.querySelectorAll(".white-key, .black-key");
        keys.forEach(key => {
            key.addEventListener("click", () => {
                clickCounter++;
                playNote(key.keyObj, clickCounter);
                showNote(key.keyObj, false);
            });
        });
        let audio = document.createElement("audio");
        audio.id = "audio_" + k_ha.file;
        audio.src = "sound/" + k_ha.file + ".mp3";
        soundDiv.appendChild(audio);
        let btn = document.createElement("input");
        btn.id = getKeyId(k_ha);
        btn.value = "?";
        btn.type = "button";
        btn.addEventListener("click", () => {
            clickCounter++;
            playNote(k_ha, clickCounter);
            showNote(k_ha, false);
        });
        pianoDiv.appendChild(btn);

        // 功能事件
        document.getElementById("func_about").addEventListener("click", () => switchAbout(true));
        document.getElementById("func_show_screenshot").addEventListener("click", () => showNote(curKeyObj, true))
        document.getElementById("func_loop").addEventListener("change", function() {
            clickCounter++;
            if (this.checked && curKeyObj != null) {
                playNote(curKeyObj, clickCounter);
                showNote(curKeyObj, false);
            }
        })
        document.getElementById("func_bpm").addEventListener("click", () => {
            document.getElementById("func_loop").checked = false;
            document.getElementById("panel_piano").style.display = "none";
            document.getElementById("panel_bpm").style.display = "block";
        });

        setTimeout(() => {
            if (window.parent && window.parent !== window.self) {
                let siteDiv = document.createElement("div");
                siteDiv.style.color = "red";
                siteDiv.style.fontStyle = "bold";
                siteDiv.innerText = "本工具地址：";
                let a = document.createElement("a");
                a.href = "https://gaifan.gitee.io/zelda-piano/";
                a.innerText = "https://gaifan.gitee.io/zelda-piano/";
                siteDiv.appendChild(a);
                document.getElementById("func").appendChild(siteDiv);
            }
        }, 5000)

        // BPM表生成
        const bpmDiv = document.getElementById("bpm");
        for (let i = 0; i < BPM_DATA.length; i++) {
            let bpmObj = BPM_DATA[i];
            let bpmTable = document.createElement("table");
            bpmTable.classList.add("bpm-table");
            let td;
            let tr;

            // 表头
            let thead = document.createElement("thead");
            bpmTable.appendChild(thead);
            tr = document.createElement("tr");
            td = document.createElement("td");
            td.classList.add("place");
            td.innerText = bpmObj.place;
            td.colSpan = BPM_TABLE_HEADER.length;
            tr.appendChild(td);
            thead.appendChild(tr);
            tr = document.createElement("tr");
            for (let j = 0; j < BPM_TABLE_HEADER.length; j++) {
                td = document.createElement("td");
                td.innerText = BPM_TABLE_HEADER[j];
                tr.appendChild(td);
            }
            thead.appendChild(tr);

            // 没用
            let tfoot = document.createElement("tfoot");
            bpmTable.appendChild(tfoot);

            // 数据
            let tbody = document.createElement("tbody");
            bpmTable.appendChild(tbody);
            for (let j = 0; j < bpmObj.data.length; j++) {
                let dataObj = bpmObj.data[j];
                tr = document.createElement("tr");
                td = document.createElement("td")
                td.innerText = dataObj.dis;
                td.classList.add("dis");
                tr.appendChild(td);
                for (let k = 0; k < dataObj.bpm.length; k++) {
                    td = document.createElement("td")
                    td.innerText = dataObj.bpm[k];
                    td.bpm = dataObj.bpm[k];
                    td.classList.add("bpm");
                    tr.appendChild(td);
                }
                tbody.appendChild(tr);
            }

            bpmDiv.appendChild(bpmTable);
        }

        // 功能事件
        document.getElementById("func_piano").addEventListener("click", () => {
            document.getElementById("panel_piano").style.display = "block";
            document.getElementById("panel_bpm").style.display = "none";
        });
        document.getElementById("input_bpm_search").addEventListener("change", () => findBPM());
        document.getElementById("input_bpm_near1").addEventListener("change", () => findBPM());
        document.getElementById("input_bpm_near2").addEventListener("change", () => findBPM());
        document.getElementById("btn_bpm_search").addEventListener("click", () => findBPM());
    }

    function switchAbout(about) {
        if ((document.getElementById("about").style.display === "none") !== about) {
            return;
        }
        if (about) {
            document.getElementById("func_loop").checked = false;
            document.getElementById("div_detail").style.display = "none";
            document.getElementById("about").style.display = "inline-block";
        } else {
            document.getElementById("div_detail").style.display = "block";
            document.getElementById("about").style.display = "none";
        }
    }

    function playNote(keyObj, counter) {
        if (counter !== clickCounter || !document.getElementById("func_play").checked) {
            return;
        }
        let audio = document.getElementById("audio_" + keyObj.file);
        audio.currentTime = 0;
        audio.play();
        if (document.getElementById("func_loop").checked) {
            setTimeout(() => playNote(keyObj, counter), 1000);
        }
    }

    function showNote(keyObj, forceRefresh) {
        if (keyObj == null) {
            setPressedKey(curKeyObj, false);
            curKeyObj = keyObj;
            return;
        }
        switchAbout(false);
        if (!forceRefresh && curKeyObj === keyObj) {
            return;
        }
        setPressedKey(curKeyObj, false);
        setPressedKey(keyObj, true);
        curKeyObj = keyObj;
        document.getElementById("note_name").innerText = keyObj.name;
        document.getElementById("note_use_count").innerText = keyObj.useCount;
        document.getElementById("note_remark").innerText = keyObj.useWall ? "需要插墙" : "";
        document.getElementById("note_screenshot").innerHTML = "";
        if (document.getElementById("func_show_screenshot").checked) {
            let img = document.createElement("img");
            img.src = "image/" + keyObj.file + ".jpg";
            document.getElementById("note_screenshot").appendChild(img);
        }
    }

    function setPressedKey(keyObj, pressed) {
        if (keyObj == null) {
            return;
        }
        if (pressed) {
            document.getElementById(getKeyId(keyObj)).classList.add("pressed-key");
        } else {
            document.getElementById(getKeyId(keyObj)).classList.remove("pressed-key");
        }
    }

    function findBPM() {
        let searchBPM = Number.parseFloat(document.getElementById("input_bpm_search").value);
        let near1BPM = Number.parseFloat(document.getElementById("input_bpm_near1").value);
        let near2BPM = Number.parseFloat(document.getElementById("input_bpm_near2").value);
        const bpmData = document.querySelectorAll(".bpm-table tbody td.bpm");
        bpmData.forEach(bpmElement => {
            bpmElement.classList.remove("near1");
            bpmElement.classList.remove("near2");
            let bpm = bpmElement.bpm;
            let d = Math.abs(searchBPM - bpm);
            let near = false;
            if (d <= near1BPM) {
                bpmElement.classList.add("near1");
                near = true;
            } else if (d <= near2BPM) {
                bpmElement.classList.add("near2");
                near = true;
            }
            if (near) {
                let state;
                if (d < 0.8) {
                    state = "♦"
                } else if (bpm > searchBPM) {
                    state = "↑";
                } else {
                    state = "↓";
                }
                bpmElement.innerText = bpm + state;
            } else {
                bpmElement.innerText = bpm;
            }
        })
    }
</script>
</body>
</html>